from . import std
from flask import render_template, redirect, request, url_for, flash
from flask_login import login_required, current_user
from ..models import Student, Course, Takes, Inputbox, Prerequisite, Bill, Section, Teaches, Openingconfig
import datetime
from .. import db
from .forms import DepositForm


@std.route('/student-home', methods=['GET', 'POST'])
@login_required
def student_home():
    # student_home界面，该界面提供链接到
    # 1. std.student_list_courses
    # 2. std.student_view_report_card
    # 3. std.student_input_box
    # 4. std.student_bill_information
    # 本界面只提供以上四个连接，不进行数据库操作
    today = datetime.datetime.today()
    name = current_user.get_name()
    greeting = name + "同学，您好！现在是" + str(today.year) + "年" + str(today.month) + "月" + str(today.day) + "日，" + str(
        today.hour) + "时" + str(
        today.minute) + "分"

    new_messages = Inputbox.query.filter(Inputbox.user_id == current_user.get_id()).filter(
        Inputbox.hasBeenRead == False).order_by(Inputbox.timestamp.desc()).all()  # 未读消息(hasBeenRead为False)
    if len(new_messages) > 0:
        flash('您有新的消息，请查看！')
    return render_template('student/student_home.html', greeting=greeting)


@std.route('/student-list-courses', methods=['GET', 'POST'])
@login_required
def student_list_courses():
    # 本路由是列出课程界面，查询出学生的可选课程和已选课程，返回这些课程
    # 其中可选课程为
    # 1. 本学期开设
    # 2. 有老师教

    # 这里不考虑该课程容量是否已满，这在std.student_register_for_course路由处理
    # 本路由仅查询出这些课程，传送到前端
    today = datetime.datetime.today()
    thisSemester = str(today.year)
    if int(today.month) < 7:
        thisSemester += "1"
    else:
        thisSemester += "2"

    take_list = Takes.query.filter(Takes.student_id == current_user.get_id()).all()
    teaches_list = Teaches.query.all()

    section_id_has_teaches = [t.section_id for t in teaches_list]
    section_id_has_choose = [t.section_id for t in take_list]
    thisSemester_section_list = Section.query.filter(Section.semester == thisSemester).all()
    section_list = []
    for s in thisSemester_section_list:
        if s.section_id not in section_id_has_choose and s.section_id in section_id_has_teaches \
                and s.course:
            section_list.append(s)

    openingobj = Openingconfig.query.first()
    opening = openingobj.value
    # 相同，但是学期不同的课程，所以这里需要查到的是section
    # 表中在当前学期开课的数据项，section表中定义了course的
    # 关系引用，可以直接得到他所对应的course对象
    # 再列出本学期已选择的课程，可供退选
    taken_course_list = Takes.query.filter(Takes.student_id == current_user.get_id(), Takes.isPrimary == True).all()
    alternative_course_list = Takes.query.filter(Takes.student_id == current_user.get_id(),
                                                 Takes.isPrimary == False).all()
    return render_template('student/student_list_courses.html',
                           open=opening,
                           section_list=section_list,
                           taken_course_list=taken_course_list,
                           alternative_course_list=alternative_course_list)


# ----------------------------------
# 2020/06/11更新
# 加入查看课程简介功能
@std.route('/student-view-course-information/<int:section_id>', methods=['GET', 'POST'])
def student_view_course_information(section_id):
    section = Section.query.filter(Section.section_id == section_id).first()
    course = section.course
    return render_template('student/student_view_course_information.html', course=course)


# ----------------------------------


# 本路由仅处理数据，没有实际界面
@std.route('/student-register-for-course/<int:section_id>/<isPrimary>', methods=['GET', 'POST'])
@login_required
def student_register_for_course(section_id, isPrimary):
    if isPrimary == "True":
        isPrimary = True
    else:
        isPrimary = False
    # 本路由解决学生选课
    # 本路由接受course_id和isPrimary两个参数，用以决定要选的课程以及是否为primary
    section = Section.query.filter(Section.section_id == section_id).first()
    course_id = section.course_id
    prerequisites_all = Prerequisite.query.filter(Prerequisite.course_id == course_id).all()

    takes = Takes.query.filter(Takes.student_id == current_user.get_id()).filter(Takes.isPrimary == True).all()
    hasTakesCourse_id = [t.course_id for t in takes]

    prerequisites = []
    for p in prerequisites_all:
        if p.pre_id not in hasTakesCourse_id:
            prerequisites.append(p)

    today = datetime.datetime.today()
    thisSemester = str(today.year)
    if int(today.month) < 7:
        thisSemester += "1"
    else:
        thisSemester += "2"

    takes = Takes.query.filter(Takes.student_id == current_user.get_id()).all()
    cntPrimary = 0
    cntNoPrimary = 0
    for t in takes:
        if t.section.semester == thisSemester:
            if t.isPrimary:
                cntPrimary += 1
            else:
                cntNoPrimary += 1

    if cntPrimary == 4 and isPrimary:
        flash("主修课程数目已达上限")
        return redirect(url_for('std.student_list_courses'))
    if cntNoPrimary == 2 and not isPrimary:
        flash("备选课程数目已达上限")
        return redirect(url_for('std.student_list_courses'))

    section = Section.query.filter(section.semester == thisSemester).all()
    thisSemesterCourse_id = [s.course_id for s in section]
    prerequisitesNoThisSemester = []
    for p in prerequisites:
        if p.pre_id not in thisSemesterCourse_id:
            prerequisitesNoThisSemester.append(p.pre_id)
    # 首先查询本课程是否有还未修的先修课，如果有，那么选课失败，则转到student_list_prerequisites.html, 在这个页面列出
    # 这些先修课；这个页面还提供链接返回到上一个路由，也就是std.student_list_courses

    if len(prerequisites) > 0:
        return render_template('student/student_list_prerequisites.html', prerequisites=prerequisites,
                               prerequisitesNoThisSemeter=prerequisitesNoThisSemester)

    # 到这里，先修课为空或者已经修过了
    # 然后查看课程容量
    # 如果满足选课条件，即选这个课的人数为10人一下
    count = len(Takes.query.filter(Takes.isPrimary and Takes.section_id == section_id).all())
    if count < 10 and isPrimary:  # 选课容量未满
        takes = Takes(student_id=current_user.get_id(), section_id=section_id, course_id=course_id,
                      isPrimary=isPrimary)
        db.session.add(takes)
        db.session.commit()

        bill = Bill(student_id=current_user.get_id(), course_id=takes.course.course_id, course_price=takes.course.price,
                    hasBeenPaid=False)
        db.session.add(bill)
        db.session.commit()
        flash('选课成功！')
    else:
        if not isPrimary:  # 选课容量已满，可以设置为备选
            takes = Takes(student_id=current_user.get_id(), section_id=section_id, course_id=course_id,
                          isPrimary=isPrimary)
            db.session.add(takes)
            db.session.commit()
            flash('成功将该课程设为备选！')
        else:
            flash('课程容量已满！选课失败！')
    # 否则，不能选课，返回到std.student_list_courses

    return redirect(url_for('std.student_list_courses'))


@std.route('/student-cancel-course/<int:section_id>/<isPrimary>', methods=['GET', 'POST'])
@login_required
def student_cancel_course(section_id, isPrimary):
    # 本路由解决退课，包括取消已选课程和已作为备选的课程
    take = Takes.query.filter(Takes.section_id == section_id).first()
    if isPrimary == "True":
        isPrimary = True
    else:
        isPrimary = False

    if take is not None:
        db.session.delete(take)
        if isPrimary:
            bill = Bill.query.filter(Bill.course_id == take.course_id).filter(
                Bill.hasBeenPaid == False).first()
            db.session.delete(bill)
        db.session.commit()
        if isPrimary:
            flash('您已成功退选该课程！')
        else:
            flash('您已成功将该课移出备选！')
        return redirect(url_for('std.student_list_courses'))
    flash('要删除的课不存在！')  # 正常不会执行到这里
    return redirect(url_for('std.student_list_courses'))


@std.route('/student-view-report-card', methods=['GET', 'POST'])
@login_required
def student_view_report_card():
    # 本路由展现成绩单
    # 通过查询Takes表，得到本学生有成绩的课程，返回takes实例，传到前端，前端展示课程名和成绩
    # 查到的课程名和成绩记录(比如为takes实例)在列表 report_card里
    report_card = Takes.query.filter(Takes.student_id == current_user.get_id(), Takes.isPrimary == True,
                                     Takes.grade is not None).all()
    return render_template('student/student_view_report_card.html', report_card=report_card)


@std.route('/student-input-box', methods=['GET', 'POST'])
@login_required
def student_input_box():
    # 获取消息列表
    # 查询input_box中id=current_user.get_id()的消息，按时间排序(最好排序)，并根据hasBeenRead分成已读消息和未读消息
    # 已读消息 old_messages，未读消息 new_messages，如果new_messages为空，则置hasUnreadMessages=True，这个参数用于决定颜色
    old_messages = Inputbox.query.filter(Inputbox.user_id == current_user.get_id()).filter(
        Inputbox.hasBeenRead == True).order_by(Inputbox.timestamp.desc()).all()
    new_messages = Inputbox.query.filter(Inputbox.user_id == current_user.get_id()).filter(
        Inputbox.hasBeenRead == False).order_by(Inputbox.timestamp.desc()).all()
    return render_template('student/student_input_box.html',
                           old_messages=old_messages,
                           new_messages=new_messages)


# input_box的辅助路由，仅处理数据，无实际界面，数据处理完成后回到input_box界面
@std.route('/student-mark-all_messages_as_read', methods=['GET', 'POST'])
@login_required
def student_mark_all_messages_as_read():
    # 本路由将该学生所有未读消息标记为已读
    # 修改数据库，将input_box里的所有id=current_user.get_id()的消息的hasBeenRead项目置为True
    # 然后返回input-box
    inputbox = Inputbox.query.filter(Inputbox.user_id == current_user.get_id()).filter(
        Inputbox.hasBeenRead == False).all()
    for item in inputbox:
        item.hasBeenRead = True

    db.session.commit()
    return redirect(url_for('std.student_input_box'))


@std.route('/student-bill-information', methods=['GET', 'POST'])
@login_required
def student_bill_information():
    # 本路由账单界面
    # 查数据库，查出本学生未支付的课程名字及其价格，计算出合计需要支付的金额，以及本学生的balance
    # 本路由仅查询，将结果返回到前端
    bill = Bill.query.filter(Bill.student_id == current_user.get_id(), Bill.hasBeenPaid == False).all()
    balance = Student.query.filter(Student.student_id == current_user.get_id()).first().balance
    items = [[b.course.course_name, b.course_price] for b in bill]  # 列表，每一项由课程名和课程金额构成
    total = sum([b.course_price for b in bill])
    return render_template('student/student_bill_information.html',
                           items=items,
                           balance=balance,
                           total=total)


@std.route('/student-deposit', methods=['GET', 'POST'])
@login_required
def student_deposit():
    # 学生充值，本路由需要学生填写表单
    # 若充值成功，则返回std.student_bill_information，否则停留在这个页面
    depositForm = DepositForm()
    if depositForm.validate_on_submit():
        if depositForm.amount.data <= 0:
            flash("请输入大于零的金额值")
            return render_template('student/student_deposit.html', form=depositForm)

        if not check_money_amount(depositForm.amount.data):
            # 不合理的金额
            flash('金额值小数点后最多两位数字！请重新输入！')
            return render_template('student/student_deposit.html', form=depositForm)

        student = Student.query.filter(Student.student_id == current_user.get_id()).first()
        student.balance += depositForm.amount.data
        db.session.add(student)
        db.session.commit()
        flash('充值成功！')
        return redirect(url_for('std.student_bill_information'))
    return render_template('student/student_deposit.html', form=depositForm)


# -------------------------------
# 2020/06/11更新
# 检查金额是否为合理的浮点数
def check_money_amount(amount):
    """
    检查金额的值是否为合理的，即小数点后最多两位数字
    :param amount: 大于0的浮点数
    :return: 金额合理返回True，不合理返回False
    """
    str_amount = str(amount)
    dot_position = str_amount.find(".", 0, len(str_amount) - 1)
    if dot_position != -1 and len(str_amount) - 1 - dot_position > 2:  # 存在小数点且小数点后超过两位
        return False
    else:
        return True  # 不存在小数点或小数点后小于两位


# -------------------------------

@std.route('/student-pay/<float:total>', methods=['GET', 'POST'])
@login_required
def student_pay(total):
    # 本路由用于学生支付学费
    # 这里规定，学生在支付时，需要保证余额不小于需支付的总金额
    # 学生只能一次支付完所有未支付课程的总金额，而不能选择部分课程支付
    student = Student.query.filter(Student.student_id == current_user.get_id()).first()
    if student.balance < total:
        flash('当前余额不足，请充值！')
        # 支付失败，金额不足，自动跳转到充值页面
        return redirect(url_for('std.student_deposit'))

    student.balance -= total  # 将学生金额扣除
    db.session.add(student)
    db.session.commit()
    # 置hasBeenPaid=True操作已修改
    bill = Bill.query.filter(Bill.student_id == current_user.get_id()).filter(Bill.hasBeenPaid == False).all()
    for i in range(len(bill)):
        bill[i].hasBeenPaid = True
    db.session.commit()

    flash('支付完成！')
    # 支付成功后，返回std.student_bill_information
    return redirect(url_for('std.student_bill_information'))
